﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace System.Peppers.UI
{
    /// <summary>
    /// Implementation of Rectangle, very similar to System.Drawing.Rectangle
    /// </summary>
    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct Rectangle
    {
        /// <summary>
        /// Instance of new Recangle(0, 0, 0, 0);
        /// </summary>
        public static readonly Rectangle Empty = new Rectangle();
        private int x;
        private int y;
        private int width;
        private int height;

        /// <summary>
        /// Ctor taking 2 integers
        /// </summary>
        /// <param name="x">X pos</param>
        /// <param name="y">Y pos</param>
        /// <param name="width">Width</param>
        /// <param name="height">Height</param>
        public Rectangle(int x, int y, int width, int height)
        {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        /// <summary>
        /// Ctor taking a Point and a Size
        /// </summary>
        /// <param name="location">Point location</param>
        /// <param name="size">Size of rectangle</param>
        public Rectangle(Point location, Size size)
        {
            this.x = location.X;
            this.y = location.Y;
            this.width = size.Width;
            this.height = size.Height;
        }

        internal static Rectangle FromLTRB(int left, int top, int right, int bottom)
        {
            return new Rectangle(left, top, right - left, bottom - top);
        }

        /// <summary>
        /// (x,y) location
        /// </summary>
        public Point Location
        {
            get
            {
                return new Point(this.X, this.Y);
            }
            set
            {
                this.X = value.X;
                this.Y = value.Y;
            }
        }

        /// <summary>
        /// Size width/height
        /// </summary>
        public Size Size
        {
            get
            {
                return new Size(this.Width, this.Height);
            }
            set
            {
                this.Width = value.Width;
                this.Height = value.Height;
            }
        }

        /// <summary>
        /// X position
        /// </summary>
        public int X
        {
            get
            {
                return this.x;
            }
            set
            {
                this.x = value;
            }
        }

        /// <summary>
        /// Y position
        /// </summary>
        public int Y
        {
            get
            {
                return this.y;
            }
            set
            {
                this.y = value;
            }
        }

        /// <summary>
        /// Width
        /// </summary>
        public int Width
        {
            get
            {
                return this.width;
            }
            set
            {
                this.width = value;
            }
        }

        /// <summary>
        /// Height
        /// </summary>
        public int Height
        {
            get
            {
                return this.height;
            }
            set
            {
                this.height = value;
            }
        }

        /// <summary>
        /// X position
        /// </summary>
        public int Left
        {
            get
            {
                return this.x;
            }
        }

        /// <summary>
        /// Y position
        /// </summary>
        public int Top
        {
            get
            {
                return this.y;
            }
        }

        /// <summary>
        /// X position + width
        /// </summary>
        public int Right
        {
            get
            {
                return (this.x + this.Width);
            }
        }

        /// <summary>
        /// Y position + Height
        /// </summary>
        public int Bottom
        {
            get
            {
                return (this.y + this.Height);
            }
        }

        /// <summary>
        /// Checks if x, y, width, height are all zero
        /// </summary>
        public bool IsEmpty
        {
            get
            {
                return ((((this.height == 0) && (this.width == 0)) && (this.x == 0)) && (this.y == 0));
            }
        }

        /// <summary>
        /// Checks equality on another Rectangle
        /// </summary>
        /// <param name="obj">Rectangle to compare</param>
        /// <returns>True if equal</returns>
        public override bool Equals(object obj)
        {
            if (!(obj is Rectangle))
            {
                return false;
            }
            Rectangle rectangle = (Rectangle)obj;
            return rectangle == this;
        }

        /// <summary>
        /// Checks if 2 rectangles are equal
        /// </summary>
        /// <param name="left">Rectangle 1</param>
        /// <param name="right">Rectangle 2</param>
        /// <returns>True if equal</returns>
        public static bool operator ==(Rectangle left, Rectangle right)
        {
            return ((((left.X == right.X) && (left.Y == right.Y)) && (left.Width == right.Width)) && (left.Height == right.Height));
        }

        /// <summary>
        /// Checks if 2 rectangles are not equal
        /// </summary>
        /// <param name="left">Rectangle 1</param>
        /// <param name="right">Rectangle 2</param>
        /// <returns>If not equal</returns>
        public static bool operator !=(Rectangle left, Rectangle right)
        {
            return !(left == right);
        }

        /// <summary>
        /// Returns true if (x, y) are within the rectangle
        /// </summary>
        /// <param name="x">x coordinate</param>
        /// <param name="y">y coordinate</param>
        /// <returns>True if contained within</returns>
        public bool Contains(int x, int y)
        {
            return ((((this.X <= x) && (x < (this.X + this.Width))) && (this.Y <= y)) && (y < (this.Y + this.Height)));
        }

        /// <summary>
        /// Returns unique hashcode for Rectangle
        /// </summary>
        /// <returns>unique function of x, y, width, height</returns>
        public override int GetHashCode()
        {
            return (((this.X ^ ((this.Y << 13) | (this.Y >> 0x13))) ^ ((this.Width << 0x1a) | (this.Width >> 6))) ^ ((this.Height << 7) | (this.Height >> 0x19)));
        }
    }
}
